#!/usr/bin/python
# -*- coding: utf-8 -*-

#-------------------------------------------------
#Create At: 2008-7-17 下午03:24:40 
#Create By: Fla.sam
#
#DESC: 
#
#-------------------------------------------------

#L-System(Lindenmayer system)是一种用字符串替代产生分形图形的算法
from Tkinter import *
from math import sin, cos, pi

class L_System:
    def __init__(self, rule):
        info = rule['S']
        for i in range(rule['iter']):
            ninfo = []
            for c in info:
                if c in rule:
                    ninfo.append(rule[c])
                else:
                    ninfo.append(c)
            info = "".join(ninfo)
        self.rule = rule
        self.info = info

    def draw(self, canvas, size=(300,300)):
        w, h  = size
        canvas.config(width = w, height = h)
        canvas.delete("all")
        line = canvas.create_line
        d = self.rule['direct']
        a = self.rule['angle']
        p = (0.0, 0.0)
        l = 1.0
        lines = []
        stack = []
        for c in self.info:
            if c in "Ff":
                r = d * pi / 180
                t = p[0] + l*cos(r), p[1] + l*sin(r)
                lines.append((p[0], p[1], t[0], t[1]))
                p = t
            elif c == "+":
                d += a
            elif c == "-":
                d -= a
            elif c == "[":
                stack.append((p,d))
            elif c == "]":
                p, d = stack[-1]
                del stack[-1]
        minx = min((x[0] for x in lines))
        maxx = max((x[0] for x in lines))
        miny = min((x[1] for x in lines))
        maxy = max((x[1] for x in lines))
        cx = (maxx + minx) / 2
        cy = (maxy + miny) / 2
        scale = min((w-10) / (maxx - minx), (h-10) / (maxy - miny))
        for x0,y0,x1,y1 in lines:
            x0 = (x0 - cx) *scale + w/2
            y0 = (y0 - cy) *scale + h/2
            x1 = (x1 - cx) *scale + w/2
            y1 = (y1 - cy) *scale + h/2
            line(x0,y0,x1,y1)
       
rules = [
    {
        "F":"F+F--F+F", "S":"F",
        "direct":0,
        "angle":60,
        "iter":5,
        "title":"Koch"
    },
    {
        "X":"X+YF+", "Y":"-FX-Y", "S":"FX",
        "direct":0,
        "angle":90,
        "iter":13,
        "title":"Dragon"
    },
    {
        "f":"F-f-F", "F":"f+F+f", "S":"f",
        "direct":0,
        "angle":60,
        "iter":7,
        "title":"Triangle"
    },
    {
        "X":"F-[[X]+X]+F[+FX]-X", "F":"FF", "S":"X",
        "direct":-45,
        "angle":50,
        "iter":20,
        "title":"Plant"
    },
    {
        "S":"X", "X":"-YF+XFX+FY-", "Y":"+XF-YFY-FX+",
        "direct":0,
        "angle":90,
        "iter":6,
        "title":"Hilbert"
    },
    {
        "S":"L--F--L--F", "L":"+R-F-R+", "R":"-L+F+L-",
        "direct":0,
        "angle":45,
        "iter":10,
        "title":"Sierpinski"
    },
   
]

def draw_rule(rule, canvas):
    def func():
        L_System(rule).draw(canvas)
    return func

root = Tk()
root.title("L-System")
menu = Menu(root)
canvas = Canvas(root)
canvas.pack()
for rule in rules:
    menu.add_command(label = rule["title"], command = draw_rule(rule, canvas))
root.config(menu=menu)
root.mainloop()